﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace KATS_Client.UI
{
    /// <summary>
    /// Represents a tab
    /// </summary>
    class Tab
    {
        /// <summary>
        /// The icons used by the system for the differing file types
        /// </summary>
        public static ImageList ExtensionIcons;
        /// <summary>
        /// Static constructor
        /// </summary>
        static Tab()
        {
            ExtensionIcons = new ImageList();
            ExtensionIcons.ColorDepth = ColorDepth.Depth32Bit;
            //ExtensionIcons.TransparentColor = new System.Drawing.Color();
            ExtensionIcons.Images.Add("Directory", Properties.Resources.Directory);
            ExtensionIcons.Images.Add("NO_FILE_ICON", Properties.Resources.FileType_unknown);
            ExtensionIcons.Images.Add("HDD_ICON", Properties.Resources.HDD);
            ExtensionIcons.Images.Add("CDROM_ICON", Properties.Resources.CDROM);
            ExtensionIcons.Images.Add("REMOVABLE_ICON", Properties.Resources.Removable_drive);
            ExtensionIcons.Images.Add("NETWORK_ICON", Properties.Resources.NetworkDrive);
            ExtensionIcons.Images.Add("FLOPPY_ICON", Properties.Resources.Floppydrive);
        }

        /// <summary>The current max unique number</summary>
        public static int UniqueMax = 0;
        /// <summary>A unique number for this tab object</summary>
        public int UniqueNumber = 0;

        /// <summary>
        /// Create a tab object
        /// </summary>
        /// <param name="Folder">The folder to display in this tab</param>
        public Tab(Window Window, Client.FileSystemObject Directory)
        {
            UniqueNumber = UniqueMax++;
            // register for folder changed events

            this.Window = Window;
            this.Directory = Directory;

            CreateTab();

            this.Window.Register(this);

            Directory_Changed += new EventHandler<EventArgs>(Tab_Directory_Changed);
        }

        /// <summary>
        /// The folder has been changed, remake the inner data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Tab_Directory_Changed(object sender, EventArgs e)
        {
            GetAndDisplayData();
        }

        /// <summary>
        /// The delete button in the context menu has been clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ContextMenu_Delete_Click(object sender, EventArgs e)
        {
            Delete();
        }

        /// <summary>
        /// The rename button in the context menu has been clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ContextMenu_Rename_Click(object sender, EventArgs e)
        {
            Rename();
        }

        /// <summary>
        /// The create directory button in the right click menu has been clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ContextMenu_CreateDirectory_Click(object sender, EventArgs e)
        {
            CreateDirectory();
        }

        /// <summary>
        /// The refresh button in the context menu has been clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ContextMenu_Refresh_Click(object sender, EventArgs e)
        {
            this.Refresh_Threaded();
        }


        /// <summary>
        /// The tabs list view
        /// </summary>
        private ListViewDragable listView = null;

        /// <summary>
        /// Build the tab page for this tab/location
        /// </summary>
        void CreateTab()
        {
            TabPage.Controls.Clear();
            TabPage.Tag = this;
            TabPage.Text = this.Directory.Name;
            //TabPage.AutoScroll = true;
            //Console.WriteLine("tab scrolL: " + TabPage.AutoScroll);

            listView = new ListViewDragable();
            listView.Dock = DockStyle.Fill;
            listView.View = View.List;
            listView.Parent = TabPage;
            listView.Tag = this;
            listView.ShowItemToolTips = true;
            listView.SmallImageList = ExtensionIcons;
            listView.LabelEdit = true;
            listView.AfterLabelEdit += new LabelEditEventHandler(listview_AfterLabelEdit);
            listView.DoubleClick += new EventHandler(listview_DoubleClick);
            listView.ContextMenuStrip = new ContextMenuStrip();
            listView.ContextMenuStrip.Tag = this;
            listView.ContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(ContextMenuStrip_Opening);
            listView.AllowDrop = true;
            listView.KeyUp += new KeyEventHandler(listview_KeyUp);
            //listview.Height = 1000;
            //listview.Scrollable = false;
            //listview.BackColor = System.Drawing.Color.Yellow;


            //CreateContextMenu();

            TabPage.Controls.Add(listView);
        }

        /// <summary>The time a label was edited</summary>
        DateTime LabelEdited = DateTime.Now;

        /// <summary>A label item is not being edited anymore</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void listview_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            LabelEdited = DateTime.Now;
            // the selected item is not being edited anymore
            ListViewDragable lvd = (ListViewDragable)sender;

            // check that only 1 item is selected
            if (lvd.SelectedItems.Count != 1)
                return;

            // then this item was not changed, so exit now
            if (e.Label == null)
                return;

            // the selected item in the list view page
            ListViewItem lvi = lvd.SelectedItems[0];

            // the old file data
            Client.FileSystemObject oldData = (Client.FileSystemObject)lvi.Tag;
            // the new name for the file/directory
            string NewName = e.Label;

            // perform the rename action
            Client.FileActions.Rename(oldData, NewName);

            string newLocation = oldData.Parent.Location + "\\" + e.Label;
            Client.FileSystemObject newData = new Client.FileSystemObject(newLocation, oldData.IsRemote, oldData.objectType);
            lvi.Tag = newData;
        }

        /// <summary>
        /// Select all the files in the tab page
        /// </summary>
        public void SelectAll()
        {
            this.listView.SelectAll();
        }

        /// <summary>
        /// A key has been released
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void listview_KeyUp(object sender, KeyEventArgs e)
        {
            bool h = false;
            switch (e.KeyCode)
            {
                case Keys.Delete:
                    // delete key pressed
                    this.Delete();
                    h = true;
                    break;
                case Keys.A:
                    if (e.Control)
                    {
                        // Ctrl + A pressed
                        // select all option
                        SelectAll();
                        h = true;
                    }
                    break;
                case Keys.F2:
                    // rename key pressed
                    this.Rename();
                    h = true;
                    break;
                case Keys.F3:
                    // search key pressed
                    this.window.searchBar.Show();
                    h = true;
                    break;
                case Keys.F:
                    if (e.Control)
                    {
                        // Ctrl + F pressed
                        // search shortcut
                        this.window.searchBar.Show();
                        h = true;
                    }
                    break;
                case Keys.Enter:
                    // enter key pressed. enter the item
                    TimeSpan ts = DateTime.Now - LabelEdited;
                    if (ts.TotalMilliseconds < 100)
                        return;
                    listview_DoubleClick(null, null);
                    h = true;
                    break;
                case Keys.Back:
                    this.MoveUpDirectory();
                    h = true;
                    break;
            }

            e.Handled = h;
        }

        /// <summary>
        /// The context menu strip has been right clicked and is about to open
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Tab tab = this;

            if (tab.listView.SelectedIndices.Count == 0 || tab.Directory.IsMyComputer)
            {
                e.Cancel = true;
                return;
            }
            CreateContextMenu();
        }

        /// <summary>
        /// Create the context menu for this tab
        /// </summary>
        void CreateContextMenu()
        {
            try
            {
                ContextMenuStrip menu = listView.ContextMenuStrip;
                menu.Items.Clear();

                ToolStripMenuItem ContextMenu_Refresh = new ToolStripMenuItem("Refresh", Properties.Resources.Refresh);
                ContextMenu_Refresh.Click += new EventHandler(ContextMenu_Refresh_Click);
                ContextMenu_Refresh.ToolTipText = "Refresh this file view";

                ToolStripMenuItem ContextMenu_CreateDirectory = new ToolStripMenuItem("Create Directory", Properties.Resources.CreateDirectory);
                ContextMenu_CreateDirectory.Click += new EventHandler(ContextMenu_CreateDirectory_Click);
                ContextMenu_CreateDirectory.ToolTipText = "Create a new directory";

                ToolStripMenuItem ContextMenu_Rename = new ToolStripMenuItem("Rename", Properties.Resources.Rename);
                ContextMenu_Rename.Click += new EventHandler(ContextMenu_Rename_Click);
                ContextMenu_Rename.ToolTipText = "Rename this file";

                ToolStripMenuItem ContextMenu_Delete = new ToolStripMenuItem("Delete", Properties.Resources.Delete);
                ContextMenu_Delete.Click += new EventHandler(ContextMenu_Delete_Click);
                ContextMenu_Delete.ToolTipText = "Delete the selected files";

                // EXTRA OBJECTS
                ToolStripMenuItem ContextMenu_Extra = new ToolStripMenuItem("More...");

                ToolStripMenuItem StripWebChars = new ToolStripMenuItem("Strip web chars");
                StripWebChars.ToolTipText = "Removes the following chars: . _ ";
                StripWebChars.Click += new EventHandler(StripWebChars_Click);

                ToolStripMenuItem CapitaliseChars = new ToolStripMenuItem("Capitalise First Chars");
                CapitaliseChars.ToolTipText = "Puts the 1st letter of each word to its capital";
                CapitaliseChars.Click += new EventHandler(CapitaliseChars_Click);

                ContextMenu_Extra.DropDownItems.Add(StripWebChars);
                ContextMenu_Extra.DropDownItems.Add(CapitaliseChars);

                // add in the movie renaming
                // only 1 item selected
                if (listView.SelectedItems.Count == 1)
                {
                    Client.FileSystemObject selectedObject = (Client.FileSystemObject)listView.SelectedItems[0].Tag;

                    if (selectedObject.IsFile)
                    {
                        ToolStripSeparator sub_Sep = new ToolStripSeparator();
                        ContextMenu_Extra.DropDownItems.Add(sub_Sep);

                        ToolStripMenuItem movieRenameMenu = new ToolStripMenuItem("Rename movie");
                        movieRenameMenu.ToolTipText = movieRenameMenu.Text;

                        string currentFilename = selectedObject.Name;
                        FileNameData.MovieData data = FileNameData.MovieData.Parse(currentFilename);

                        ToolStripMenuItem movieRenameButton = new ToolStripMenuItem(data.FormatedFilename);
                        movieRenameButton.ToolTipText = "Rename the movie to " + movieRenameButton.Text;
                        movieRenameButton.Tag = selectedObject;
                        movieRenameButton.Click += new EventHandler(movieRename_Click);

                        movieRenameMenu.DropDownItems.Add(movieRenameButton);
                        ContextMenu_Extra.DropDownItems.Add(movieRenameMenu);
                    }
                }
                // EXTRA OBJECTS END

                ToolStripSeparator separator1 = new ToolStripSeparator();

                ToolStripMenuItem copyTo = new ToolStripMenuItem("Copy To...", Properties.Resources.Copy);
                AddOtherTabsToContextMenu(copyTo);

                ToolStripSeparator separator2 = new ToolStripSeparator();

                ToolStripMenuItem moveTo = new ToolStripMenuItem("Move To...", Properties.Resources.Move);
                AddOtherTabsToContextMenu(moveTo);



                menu.Items.Add(ContextMenu_Refresh);
                menu.Items.Add(ContextMenu_CreateDirectory);
                menu.Items.Add(ContextMenu_Rename);
                menu.Items.Add(ContextMenu_Delete);
                menu.Items.Add(ContextMenu_Extra);

                menu.Items.Add(separator1);

                menu.Items.Add(copyTo);
                menu.Items.Add(separator2);
                menu.Items.Add(moveTo);


                // the predicted area to place the file
                ListViewItem lvi = listView.SelectedItems[0];
                Client.FileSystemObject fso = (Client.FileSystemObject)lvi.Tag;
                if (fso.IsFile)
                {
                    FileNameData.PredictionResult result = FileNameData.FindFileLocation.Parse(fso.Name);
                    if (result != null)
                    {
                        // then a valid guess was generated for this file name
                        string name = string.Format("{0} - {1}%", result.Name, result.PercentageSimilarity);

                        ToolStripSeparator sep = new ToolStripSeparator();

                        ToolStripMenuItem predictive = new ToolStripMenuItem(name, Properties.Resources.Move);
                        predictive.Tag = new CopyOrMoveAction(false, result.Directory);
                        predictive.Click += new EventHandler(contextMenu_copy_move_Click);
                        predictive.ToolTipText = "Move this file";

                        if (result.PercentageSimilarity < 60)
                        {
                            predictive.Name = "Override";
                            predictive.Text = "Override";
                            predictive.ToolTipText = "Lack of confidence. If this is correct, then click";
                            ToolStripMenuItem unsure = new ToolStripMenuItem(name, Properties.Resources.Move);
                            unsure.ForeColor = System.Drawing.Color.Gray;
                            unsure.DropDownItems.Add(predictive);
                            unsure.ToolTipText = "Can not predict target directory";
                            menu.Items.Add(sep);
                            menu.Items.Add(unsure);
                        }
                        else
                        {
                            menu.Items.Add(sep);
                            menu.Items.Add(predictive);
                        }

                    }
                }
            }
            catch (ArgumentException e)
            {
                if (e.Message == "Illegal characters in path.")
                {
                    // illegal filename
                    foreach (ToolStripItem i in listView.ContextMenuStrip.Items)
                    {
                        i.Enabled = false;
                    }
                }
                else
                {
                    throw e;
                }
            }


        }

        /// <summary>The movie has been selected to be renamed</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void movieRename_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = (ToolStripMenuItem)sender;

            string newname = item.Text;
            Client.FileSystemObject orig = (Client.FileSystemObject)item.Tag;

            Client.FileSystemObject newFilesystemObject = Client.FileActions.Rename(orig, newname);
            this.Refresh_Threaded();
        }

        /// <summary>
        /// Capitalise the first char of each word
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void CapitaliseChars_Click(object sender, EventArgs e)
        {
            CapitaliseChars();
        }

        /// <summary>
        /// Capitalise the 1st char of each word
        /// </summary>
        void CapitaliseChars()
        {
            foreach (ListViewItem lvi in this.listView.SelectedItems)
            {
                Client.FileSystemObject obj = (Client.FileSystemObject)lvi.Tag;
                bool isFile = obj.IsFile;

                string Name = lvi.Text;

                // get the extension, if is a file, and put it to lowercase
                string extension = string.Empty;
                if (isFile)
                {
                    extension = (new System.IO.FileInfo(Name)).Extension;
                    extension.ToLower();
                    Name = Name.Remove(Name.Length - extension.Length);
                }



                string newName = string.Empty; // make the new filename in this variable

                string[] words = Name.Split(new char[] { ' ' });
                // using the space split msg, cap the 1st letter of each word
                for (int i = 0; i < words.Length; i++)
                {
                    string s = words[i];
                    string S = "" + s[0]; // get the 1st char as a string
                    S = S.ToUpper(); // convert it to upper case

                    string CapLetter = S + s.Substring(1); // add on the rest of the string
                    newName += CapLetter + " "; // add it to the new filename variable
                }

                newName = newName.Trim(); // remove the trailing space

                if (isFile) // add the extension back on if it is a file
                    newName += extension;

                // rename this object
                Client.FileSystemObject newFilesystemObject = Client.FileActions.Rename(obj, newName);

                // update the UI's properties
                lvi.Text = newName;
                lvi.Tag = newFilesystemObject;
            }
        }

        /// <summary>
        /// The strip web chars button has been clicked from the context menu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void StripWebChars_Click(object sender, EventArgs e)
        {
            StripWebChars();
        }

        /// <summary>
        /// Strip out any webchars from the selected objects
        /// </summary>
        void StripWebChars()
        {
            foreach (ListViewItem lvi in this.listView.SelectedItems)
            {
                Client.FileSystemObject o = (Client.FileSystemObject)lvi.Tag;

                bool isFile = false;
                string extension = string.Empty;
                string objectname = lvi.Text;
                if (o.objectType == Client.FileSystemObjectTypes.File)
                {
                    isFile = true;

                    System.IO.FileInfo fi = new System.IO.FileInfo(lvi.Text);
                    extension = fi.Extension;

                    // remove the file extension from the filename
                    objectname = objectname.Replace(extension, "");
                    // save the extension in lowercase
                    extension = extension.ToLower();
                }


                string[] CharsToRemove = new string[] { "_", "." };

                string newname = objectname;
                foreach (string c in CharsToRemove)
                {
                    newname = newname.Replace(c, " ");
                }

                while (newname.IndexOf("  ") >= 0)
                {
                    newname = newname.Replace("  ", " ");
                }
                newname = newname.Trim();

                // add on the extension again
                if (isFile)
                    newname += extension;

                Client.FileSystemObject newFilesystemObject = Client.FileActions.Rename(o, newname);

                lvi.Text = newname;
                lvi.Tag = newFilesystemObject;
            }
        }

        /// <summary>
        /// Adds tool strip menu items for the other tabs to the menu item provided
        /// </summary>
        /// <param name="menuItem">The menu item to add the other tabs into </param>
        void AddOtherTabsToContextMenu(ToolStripMenuItem menuItem)
        {
            // check which menu system this is for
            bool isCopyMenu = false;
            if (menuItem.Text.ToLower().Contains("copy"))
                isCopyMenu = true;

            List<Tab> tabs = new List<Tab>();
            foreach (Window w in WindowManager.Windows)
            {
                foreach (Tab t in w.Tabs)
                {
                    tabs.Add(t);
                }
            }
            string dirString = this.Directory.ToString();
            var sortedTabs = from t in tabs
                             where t.Directory.IsMyComputer == false && t.Directory.ToString() != dirString
                             orderby t.Directory.Name
                             select t;

            List<ToolStripMenuItem> localItems = new List<ToolStripMenuItem>();
            List<ToolStripMenuItem> remoteItems = new List<ToolStripMenuItem>();

            foreach (Tab tabdata in sortedTabs)
            {
                bool alreadyAdded = false;

                string currentTabString = tabdata.Directory.ToString();
                if (!tabdata.Directory.IsRemote)
                {
                    foreach (ToolStripMenuItem i in localItems)
                    {
                        CopyOrMoveAction t = (CopyOrMoveAction)i.Tag;
                        if (t.ToString() == currentTabString)
                        {
                            alreadyAdded = true;
                            break;
                        }
                    }
                }
                else
                {
                    foreach (ToolStripMenuItem i in remoteItems)
                    {
                        CopyOrMoveAction t = (CopyOrMoveAction)i.Tag;
                        if (t.ToString() == currentTabString)
                        {
                            alreadyAdded = true;
                            break;
                        }
                    }
                }

                // if there is already an item for this set, do not add it again
                if (alreadyAdded)
                    continue;



                ToolStripMenuItem sub = new ToolStripMenuItem(tabdata.Directory.Name);
                sub.Tag = new CopyOrMoveAction(isCopyMenu, tabdata.Directory);
                sub.Click += new EventHandler(contextMenu_copy_move_Click);

                if (isCopyMenu)
                {
                    if (tabdata.Directory.IsRemote)
                        sub.Image = Properties.Resources.CopyRight;
                    else
                        sub.Image = Properties.Resources.CopyLeft;
                }
                else
                {
                    if (tabdata.Directory.IsRemote)
                        sub.Image = Properties.Resources.MoveRight;
                    else
                        sub.Image = Properties.Resources.MoveLeft;
                }

                if (tabdata.Directory.IsRemote)
                {
                    // remote item
                    remoteItems.Add(sub);
                }
                else
                {
                    // not remote so local
                    localItems.Add(sub);
                }
            }

            // add the prefix to the list
            ToolStripMenuItem localTitle = new ToolStripMenuItem("Local directories...");
            localTitle.Enabled = false;
            menuItem.DropDownItems.Add(localTitle);

            // now add all the local items to the list
            foreach (ToolStripMenuItem i in localItems)
                menuItem.DropDownItems.Add(i);


            ToolStripSeparator separator = new ToolStripSeparator();
            menuItem.DropDownItems.Add(separator);

            ToolStripMenuItem remoteTitle = new ToolStripMenuItem("Remote directories...");
            remoteTitle.Enabled = false;
            menuItem.DropDownItems.Add(remoteTitle);

            // now add all the remote items to the list
            foreach (ToolStripMenuItem i in remoteItems)
                menuItem.DropDownItems.Add(i);
        }

        /// <summary>A submenu item in the context lists was clicked</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void contextMenu_copy_move_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = (ToolStripMenuItem)sender;

            CopyOrMoveAction data = (CopyOrMoveAction)item.Tag;

            Client.FileSystemObject targetDirectory = data.TargetDirectory;
            bool isCopy = data.isCopy;

            // move or copy the selected items in this tabpage to the targetTab location
            if (listView.SelectedItems.Count > 0)
            {
                // develop list of objects to move/copy to the target directory
                List<Client.FileSystemObject> selectedObjects = new List<KATS_Client.Client.FileSystemObject>(listView.SelectedIndices.Count);
                foreach (ListViewItem lvi in listView.SelectedItems)
                {
                    Client.FileSystemObject objectData = (Client.FileSystemObject)lvi.Tag;
                    selectedObjects.Add(objectData);
                }

                // make the action object
                Threaded_Queuing_MoveCopy movecopydata = new Threaded_Queuing_MoveCopy(selectedObjects, targetDirectory, isCopy);
                // start the action
                movecopydata.Perform();
            }
        }

        /// <summary>Move the tab up 1 directory</summary>
        public void MoveUpDirectory()
        {
            if (Directory.IsMyComputer)
                return;
            System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(Directory.Location);
            if (di.Root.ToString() == di.ToString())
            {
                // then currently at the root directory
                // so move to the my computer screen
                this.MoveTab("");
            }
            else
            {
                // move to parent folder
                Client.FileSystemObject obj = new Client.FileSystemObject(di.Parent.FullName, this.Directory.IsRemote, KATS_Client.Client.FileSystemObjectTypes.Directory);
                this.Directory = obj;
            }
        }

        /// <summary>Delete the selected items in this tab</summary>
        public void Delete()
        {
            ListView.SelectedListViewItemCollection selectedItems = listView.SelectedItems;
            if (selectedItems.Count > 0)
            {
                DeleteConfirmationDialog DCD;
                if (selectedItems.Count > 1)
                {
                    DCD = new DeleteConfirmationDialog(selectedItems.Count);
                }
                else
                {
                    DCD = new DeleteConfirmationDialog(selectedItems[0].Text);
                }

                if (DCD.ShowDialog() == DialogResult.Yes)
                {
                    // user selected yes from the dialog prompt
                    // so queue up the files to be deleted
                    foreach (ListViewItem item in selectedItems)
                    {
                        Client.FileSystemObject fso = (Client.FileSystemObject)item.Tag;
                        Client.FileActionsQueue.Delete(fso);
                    }
                }
            }
        }

        /// <summary>Rename the currently selected item</summary>
        public void Rename()
        {
            ListView.SelectedListViewItemCollection selectedItems = listView.SelectedItems;
            if (selectedItems.Count == 1)
            {
                selectedItems[0].BeginEdit();
                return;
            }
        }

        /// <summary>Create a new directory in this tab</summary>
        public void CreateDirectory()
        {
            if (!Directory.IsMyComputer)
            {
                string defaultName = "New Directory";

                // so create the directory
                string location = this.Directory.Location + "\\" + defaultName;
                Client.FileSystemObject fso = new KATS_Client.Client.FileSystemObject(location, this.Directory.IsRemote, KATS_Client.Client.FileSystemObjectTypes.Directory);
                // create the empty directory, do not auto-refresh
                Client.FileActions.CreateDirectory(fso, false);

                // manually add a directory object to the listview
                ListViewItem lvi = DirectoryData.MakeItem(fso.Name, fso.Name, fso, "Directory", "Directory");
                this.listView.Items.Add(lvi);


                // clear the selected items
                listView.SelectedIndices.Clear();
                // add the final item to the list, as this is were the directory is
                listView.SelectedIndices.Add(listView.Items.Count - 1);

                // now start renaming it
                Rename();
            }
        }

        /// <summary>Refresh the data displayed in this tab in a new thread</summary>
        public void Refresh_Threaded()
        {
            Thread refresh = new Thread(new ThreadStart(Refresh));
            refresh.Name = "Refreshing tab";
            refresh.IsBackground = true;
            refresh.Start();
        }

        /// <summary>Refresh the data displayed in this tab</summary>
        public void Refresh()
        {
            this.GetAndDisplayData();
        }

        /// <summary>When an item is double clicked in the list this triggers</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void listview_DoubleClick(object sender, EventArgs e)
        {
            if (listView.SelectedItems.Count > 0)
            {
                ListViewItem item = listView.SelectedItems[0];
                Client.FileSystemObject fso = (Client.FileSystemObject)item.Tag;

                if (fso.IsDirectory)
                {
                    // then is a directory or hdd so enter this folder
                    this.Directory = fso;
                }
                else if (fso.IsFile)
                {
                    //FileNameData.FileNameInfo.Parse(fso.Name);
                    Console.WriteLine(TabPage.HorizontalScroll.Value);
                }
            }
        }

        /// <summary>The data for this directory</summary>
        DirectoryData DirectoryData = null;

        /// <summary>The delegate used to safely redraw the tab data</summary>
        delegate void Delegate_DisplayData();


        /// <summary>Fill the tabpage with the items</summary>
        public void GetAndDisplayData()
        {
            // get the data from filesystem and create the list view items
            DirectoryData = new DirectoryData(this.Directory);
            DateTime dt = DateTime.Now;
            DirectoryData.GetData();
            TimeSpan ts = DateTime.Now - dt;
            dt = DateTime.Now;
            DirectoryData.CreateListViewItems();
            TimeSpan ts2 = DateTime.Now - dt;

            //Console.WriteLine(ts.TotalMilliseconds + "ms to get data. " + ts2.TotalMilliseconds + "ms to process " + DirectoryData.ListViewItems.Count + "items");

            // display the new data
            DisplayData();

        }

        /// <summary>Display the current data</summary>
        public void DisplayData()
        {
            if (TabPage.InvokeRequired)
            {
                //Console.WriteLine("invoked.     Thread: " + System.Threading.Thread.CurrentThread.Name + " " + TabPage.IsHandleCreated);
                TabPage.BeginInvoke(new Delegate_DisplayData(DisplayData2));
                //TabPage.Invoke(new Delegate_FillData(FillData2));
            }
            else
            {
                //Console.WriteLine("not invoked. Thread: " + System.Threading.Thread.CurrentThread.Name + " " + TabPage.IsHandleCreated);
                DisplayData2();
            }
        }

        /// <summary>Fill the tabpage with the items</summary>
        private void DisplayData2()
        {
            try
            {
                // change the tabs name
                TabPage.Text = Directory.Name;

                this.listView.BeginUpdate(); // dont redrawn while adding all these items
                //DateTime dt = DateTime.Now;
                if (DirectoryData == null)
                {
                    Console.WriteLine("DATA MISSING UI.TAB.DirectoryData. [line 885]");
                    return;
                }
                if (DirectoryData.ListViewItems == null)
                {
                    DirectoryData.CreateListViewItems();
                }
                ListViewItem[] items = DirectoryData.ListViewItems.ToArray();
                ListViewItem[] filtered = FilterItems(items);
                UpdateListViewItems(filtered);
                //TimeSpan ts = DateTime.Now - dt;
                //Console.WriteLine("Took " + ts.TotalMilliseconds + "ms to add "+ DirectoryData.ListViewItems.Count +" items");
                this.listView.EndUpdate();
                if (this.listView.Items.Count > 0)
                {
                    this.listView.Items[0].EnsureVisible();
                }
                // resize the column headers
                //listView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);


                if (Window.tabControl.SelectedTab == this.TabPage)
                {
                    // this window is the one that is being displayed
                    // so change the location bar for this window
                    Window.Update_LocationBox();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        /// <summary>
        /// Filter the items according to the 
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        ListViewItem[] FilterItems(ListViewItem[] items)
        {
            if (!window.searchBar.Visible)
                return items;
            string msg = window.searchBar.Text;
            if (msg == string.Empty)
                return items;
            msg = msg.ToLower();
            string[] words = msg.Split(new char[] { ' ' });

            List<ListViewItem> output = new List<ListViewItem>(items.Length);



            // performs filtering based on each space separated word 
            // must exist in the text to pass
            foreach (ListViewItem lvi in items)
            {
                bool valid = true;
                foreach (string s in words)
                {
                    if (lvi.Text.ToLower().IndexOf(s) == -1)
                    {
                        // this item does not contain a word
                        valid = false;
                        break;
                    }
                }
                if (valid)
                {
                    // is valid. so add to output set
                    output.Add(lvi);
                }
            }

            return output.ToArray();
        }

        /// <summary>
        /// Update the list view items
        /// </summary>
        /// <param name="items"></param>
        private void UpdateListViewItems(ListViewItem[] items)
        {
            //this.listView.Items.Clear();
            //this.listView.Items.AddRange(DirectoryData.ListViewItems.ToArray());

            int currentMax = listView.Items.Count;
            int min = currentMax;
            bool add = true;
            if (min > items.Length)
            {
                add = false;
                min = items.Length;
            }

            for (int i = 0; i < min; i++)
            {
                Client.FileSystemObject o1 = (Client.FileSystemObject)listView.Items[i].Tag;
                Client.FileSystemObject o2 = (Client.FileSystemObject)items[i].Tag;
                if (o1.ToString() == o2.ToString())
                    continue;

                listView.Items[i] = (ListViewItem)items[i].Clone();
            }

            if (add)
            {
                // add in the remaining new items
                for (int i = min; i < items.Length; i++)
                {
                    listView.Items.Add(items[i]);
                }
            }
            else
            {
                // delete the remaining old items
                for (int i = currentMax - 1; i >= min; i--)
                {
                    listView.Items.RemoveAt(i);
                }
            }

        }


        /// <summary>
        /// Add an file extension's icon image to the image list
        /// </summary>
        /// <param name="fileName">The file to add</param>
        /// <returns>The key for the ImageList</returns>
        public static string AddExtension(string fileName)
        {
            fileName = fileName.Replace("?", "#");
            System.IO.FileInfo fi = new System.IO.FileInfo(fileName);
            string extension = fi.Extension;
            if (extension == string.Empty)
            {
                // the file has no extension
                return "NO_FILE_ICON";
            }
            else
            {
                lock (ExtensionIcons)
                {
                    if (ExtensionIcons.Images.Keys.Contains(extension))
                    {
                        // then this extension is already in the list
                        return extension;
                    }
                    else
                    {
                        // this extension is not currently in the list
                        // so get it, add it to list
                        ExtensionIcons.Images.Add(extension, InterOp.ShellIcon.GetSmallIcon(extension));
                        return extension;
                    }
                }
            }
        }

        /// <summary>Remove all file extension images for filetypes</summary>
        public static void RemoveFileExtensionImages()
        {
            ImageList.ImageCollection exts = Tab.ExtensionIcons.Images;
            for (int i = exts.Count - 1; i >= 0; i--)
            {
                if (i >= exts.Keys.Count)
                    continue;
                string s = exts.Keys[i];
                if (s[0] == '.')
                {
                    // the 1st char of the key is a dot
                    // so this image is a file extension
                    Tab.ExtensionIcons.Images.RemoveAt(i);
                }
            }
        }


        /// <summary>
        /// The window this belongs in
        /// </summary>
        private Window window = null;

        /// <summary>
        /// The window this belongs in 
        /// </summary>
        public Window Window
        {
            get { return window; }
            set
            {
                this.window = value;

                if (Window_Changed != null)
                    Window_Changed(new object(), new EventArgs());
            }
        }

        /// <summary>
        /// The window has been changed
        /// </summary>
        public event EventHandler<EventArgs> Window_Changed;

        /// <summary>
        /// The folder this tab page represents
        /// </summary>
        private Client.FileSystemObject directory;

        /// <summary>
        /// The folder this tab page represents
        /// </summary>
        public Client.FileSystemObject Directory
        {
            get { return directory; }
            set
            {
                directory = value;
                if (Directory_Changed != null)
                    Directory_Changed(new object(), new EventArgs());
            }
        }

        /// <summary>
        /// The sub directories in this tab
        /// </summary>
        public Client.FileSystemObject[] Directories
        {
            get
            {
                // get a collection of all the sub directories displayed in this tab
                List<Client.FileSystemObject> fsos = new List<KATS_Client.Client.FileSystemObject>();

                foreach (ListViewItem lvi in listView.Items)
                {
                    // check each list view item if its tagged as a directory
                    if (lvi == null)
                        continue;
                    if (lvi.Tag == null)
                        continue;
                    Client.FileSystemObject fso = (Client.FileSystemObject)lvi.Tag;
                    if (fso.IsDirectory)
                    {
                        // if so, add it to the array to be returned
                        fsos.Add(fso);
                    }
                }
                return fsos.ToArray();
            }
        }

        /// <summary>
        /// Change the directory of this tab
        /// </summary>
        /// <param name="Directory">The new directory</param>
        public void MoveTab(string Directory)
        {
            this.Directory = new Client.FileSystemObject(Directory, this.Directory.IsRemote, Client.FileSystemObjectTypes.Directory);
            if (Directory_Changed != null)
                Directory_Changed(new object(), new EventArgs());
        }

        /// <summary>
        /// The folder has been changed
        /// </summary>
        public event EventHandler<EventArgs> Directory_Changed;

        /// <summary>
        /// The tab page for this object
        /// </summary>
        public TabPage TabPage = new TabPage();




        #region Object Overrides
        /// <summary>
        /// To string override
        /// </summary>
        /// <returns>String representation</returns>
        public override string ToString()
        {
            return Directory.ToString();
        }

        /// <summary>
        /// Get the hash code for this object
        /// </summary>
        /// <returns>Object's Hash Code</returns>
        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }
        #endregion
    }
}
